﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using XNADash.Textures;
using XNADash.Sound;

namespace XNADash.BoardBlocks
{
    public class BaseBlock
    {
        public int X;
        public int Y;
        public bool Moved = false;

        private DashBoard _board;
        public DashBoard Board { get { return _board; } set { _board = value; } }
        //public DashBoard Board { get; set; }

        protected bool _canBeConsumed = false;
        public virtual bool CanBeConsumed
        {
            get
            {
                return _canBeConsumed;
            }
        }

        public virtual bool CanBePushed
        {
            get
            {
                return false;
            }
        }

        public virtual bool CanExplode
        {
            get
            {
                return true;
            }
        }

        public virtual bool TriggersExplosion
        {
            get
            {
                return true;
            }
        }

        public virtual bool OthersFallFrom
        {
            get
            {
                return false;
            }
        }

        public virtual bool CanBeLifted
        {
            get
            {
                return false;
            }
        }

        protected virtual GameTexture BlockTexture
        {
            get
            {
                return GameTexture.Empty;
            }
        }

        public virtual Texture2D Texture
        {
            get
            {
                return TextureFactory.Instance.GetTexture( this.BlockTexture );
            }
        }

        public BaseBlock GetNeighbour( Directions Direction )
        {
            return GetNeighbour( GetNeighbourDeltaX( Direction ), GetNeighbourDeltaY( Direction ) );
        }

        public BaseBlock GetNeighbour( int dX, int dY )
        {
            int NewX = this.X + dX;
            int NewY = this.Y + dY;

            if ( NewX < 0 || NewX > this.Board.Width  ||
                 NewY < 0 || NewY > this.Board.Height 
                )
                return new OutOfBoardBlock() { Board = this.Board };

            return Board[NewX,NewY].FirstOrDefault();
        }

        public void MoveTo( Directions Direction )
        {
            this.Board[this.X,this.Y].Remove( this );

            this.X += GetNeighbourDeltaX( Direction );
            this.Y += GetNeighbourDeltaY( Direction );
            this.Moved = true;

            this.Board[this.X,this.Y].Add( this );
        }

        protected int GetNeighbourDeltaX( Directions Direction )
        {
            switch ( Direction )
            {
                case Directions.NW:
                case Directions.W:
                case Directions.SW:
                    return -1;

                case Directions.NE:
                case Directions.E:
                case Directions.SE:
                    return +1;

                default:
                    return 0;
            }
        }

        protected int GetNeighbourDeltaY( Directions Direction )
        {
            switch ( Direction )
            {
                case Directions.NW:
                case Directions.N:
                case Directions.NE: 
                    return -1; 

                case Directions.SW: 
                case Directions.S: 
                case Directions.SE:
                    return +1;

                default:
                    return 0;
            }
        }

        public virtual void ExplodeIfMust()
        {
            if ( this.CanExplode && this.MustExplode )
            {
                this.ExplodeNeighbour( Directions.None );
                return;
            }
        }

        public virtual void ApplyPhysics()
        {
            this.ExplodeIfMust();
        }

        const int EXPLODEMAX = 3;
        private int explodeCount = 0;

        public bool MustExplode
        {
            get
            {
                if ( this.explodeCount == 0 )
                    return false;
                else 
                 return this.explodeCount++ >= EXPLODEMAX;
            }
            set
            {
                if ( value == true )
                    this.explodeCount = 1;
            }
        }


        public void ExplodeNeighbour( Directions Direction )
        {
            bool ShortExplosion = Direction == Directions.S || Direction == Directions.E;

            BaseBlock neighbour = this.GetNeighbour( Direction );
            if ( neighbour == null )
            {
                this.Board.AddBlock( new BoomBlock( ShortExplosion ) { X = this.X + this.GetNeighbourDeltaX( Direction ), Y = this.Y + this.GetNeighbourDeltaY( Direction ) } );
            }
            if ( neighbour != null &&
                 neighbour.CanExplode
                )
            {
                if ( Direction == Directions.None )
                {
                    this.Board.RemoveBlock( neighbour );
                    this.Board.AddBlock( new BoomBlock( ShortExplosion ) { X = this.X + this.GetNeighbourDeltaX( Direction ), Y = this.Y + this.GetNeighbourDeltaY( Direction ) } );
                }
                else
                {
                    neighbour.MustExplode = true;
                    neighbour.Moved = true;
                }
            }
        }

        public override string ToString()
        {
            return "?";
        }
    }

    public enum Directions { None, NW, N, NE, W, E, SW, S, SE }
}
